#pragma once

#include <stdint.h>

/* SBI return error codes */
#define SBI_SUCCESS 0
#define SBI_ERR_FAILURE -1
#define SBI_ERR_NOT_SUPPORTED -2
#define SBI_ERR_INVALID_PARAM -3
#define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_ERR_NO_SHMEM -9

struct sbiret
{
    long error;
    long value;
};

enum sbi_ext_id
{
    SBI_EXT_0_1_SET_TIMER = 0x0,
    SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
    SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
    SBI_EXT_0_1_CLEAR_IPI = 0x3,
    SBI_EXT_0_1_SEND_IPI = 0x4,
    SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
    SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
    SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
    SBI_EXT_0_1_SHUTDOWN = 0x8,

    SBI_EXT_BASE = 0x10,
    SBI_EXT_TIME = 0x54494D45,
    SBI_EXT_IPI = 0x735049,
    SBI_EXT_RFENCE = 0x52464E43,
    SBI_EXT_HSM = 0x48534D,
    SBI_EXT_SRST = 0x53525354,
    SBI_EXT_SUSP = 0x53555350,
    SBI_EXT_PMU = 0x504D55,
    SBI_EXT_DBCN = 0x4442434E,
    SBI_EXT_STA = 0x535441,
    SBI_EXT_NACL = 0x4E41434C,

    /* Experimentals extensions must lie within this range */
    SBI_EXT_EXPERIMENTAL_START = 0x08000000,
    SBI_EXT_EXPERIMENTAL_END = 0x08FFFFFF,

    /* Vendor extensions must lie within this range */
    SBI_EXT_VENDOR_START = 0x09000000,
    SBI_EXT_VENDOR_END = 0x09FFFFFF,
};

enum sbi_ext_dbcn_fid
{
    SBI_EXT_DBCN_CONSOLE_WRITE = 0,
    SBI_EXT_DBCN_CONSOLE_READ = 1,
    SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2,
};

enum sbi_ext_hsm_fid
{
    SBI_EXT_HSM_HART_START = 0,
    SBI_EXT_HSM_HART_STOP,
    SBI_EXT_HSM_HART_STATUS,
    SBI_EXT_HSM_HART_SUSPEND,
};

struct sbiret __sbi_ecall(unsigned long arg0, unsigned long arg1,
                          unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5,
                          int fid, int ext);

#define sbi_ecall(e, f, a0, a1, a2, a3, a4, a5) \
    __sbi_ecall(a0, a1, a2, a3, a4, a5, f, e)

void sbi_init(void);

void sbi_set_timer(uint64_t stime_value);
void sbi_console_putchar(int ch);

int sbi_err_map_linux_errno(int err);
